package com.wxw.BaseLibrary.element;

import android.util.Log;
import com.wxw.BaseLibrary.tool.FileUtil;
import com.wxw.BaseLibrary.tool.L;
import com.wxw.BaseLibrary.tool.SystemTool;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 *
 * @author david
 * @date 2014-05-29
 */
public class JsonProperty {
    private JsonPropertyType _type;
    private String _value;
    private JsonObject _object;
    private List<JsonProperty> _list;
    private boolean _bool;
    private double _number;
    private int _integer;

    public JsonProperty()
    {
        super();
        this._type = JsonPropertyType.Null;
        this._value = null;
        this._object = null;
        this._list = null;
    }

    public JsonProperty(Object value)
    {
        super();
        this.setValue(value);
    }


    public JsonProperty(String jsonString)
    {
        super();
        this.parse(jsonString);
    }


    /**
     * Json字符串解析
     * @param jsonString
     */
    public void parse(String jsonString)
    {
        if (jsonString == null) {
            this.setValue(null);
        } else if ("".equals(jsonString)) {
            this.setValue("");
        } else {
            //jsonString = jsonString.Replace("\t", "");
            //jsonString = jsonString.Replace("\n", "");
            //jsonString = jsonString.Replace("\r", "");
            jsonString = jsonString.trim();
            char first = jsonString.charAt(0);
            char last = jsonString.charAt(jsonString.length() - 1);
            if (first == '[' && last == ']') {
                this.setValue(this.parseArray(jsonString));
            } else if (first == '{' && last == '}') {
                this.setValue(this.parseObject(jsonString));
            } else if ((first == '\'' || first == '"') && first == last) {
                this.setValue(this.parseString(jsonString));
            } else if ("true".equals(jsonString.toLowerCase()) || "false".equals(jsonString.toLowerCase())) {
                this.setValue("true".equals(jsonString.toLowerCase()) ? true : false);
            } else if (jsonString==null) {
                this.setValue(null);
            } else if (jsonString.indexOf(".")<0){
                int i = 0;
                try{
                    i = Integer.parseInt(jsonString);
                    this.setValue(i);
                } catch (Exception e) {
                    this.setValue(jsonString);
                }
            } else {
                double d = 0;
                try {
                    d = Double.parseDouble(jsonString);
                    this.setValue(d);
                } catch (Exception e) {
                    this.setValue(jsonString);
                }
            }
        }
    }

    /**
     * Json Array解析
     * @param jsonString
     * @return
     */
    private List<JsonProperty> parseArray(String jsonString)
    {
        List<JsonProperty> list = new ArrayList<JsonProperty>();
        int len = jsonString.length();
        StringBuilder sb = new StringBuilder();
        Stack<Character> stack = new Stack<Character>();
        Stack<Character> stackType = new Stack<Character>();
        boolean conver = false;
        char cur;
        for (int i = 1; i <= len - 2; i++)
        {
            cur = jsonString.charAt(i);

            if (Character.isSpaceChar(cur) && stack.size() == 0 && stackType.size() == 0)
            {
                ;
            }
            else if ((cur == '\'' && stack.size() == 0 && !conver && stackType.size() == 0) || (cur == '\"' && stack.size() == 0 && !conver && stackType.size() == 0))
            {
                sb.setLength(0);
                sb.append(cur);
                stack.push(cur);
            }
            else if (cur == '\\' && stack.size() > 0 && !conver)
            {
                sb.append(cur);
                conver = true;
            }
            else if (conver == true)
            {
                conver = false;

                if (cur == 'u')
                {
                    sb.append(new char[] { cur, jsonString.charAt(i + 1), jsonString.charAt(i + 2), jsonString.charAt(i + 3) });
                    i += 4;
                }
                else
                {
                    sb.append(cur);
                }
            }
            else if ((cur == '\'' || cur == '\"') && !conver && stack.size() > 0 && stack.peek().equals(cur) && stackType.size() == 0)
            {
                sb.append(cur);
                list.add(new JsonProperty(sb.toString()));
                stack.pop();
            }
            else if ((cur == '[' || cur == '{') && stack.size() == 0)
            {
                if (stackType.size() == 0)
                {
                    sb.setLength(0);
                }
                sb.append(cur);
                stackType.push((cur == '[' ? ']' : '}'));
            }
            else if ((cur == ']' || cur == '}') && stack.size() == 0 && stackType.size() > 0 && stackType.peek().equals(cur))
            {
                sb.append(cur);
                stackType.pop();
                if (stackType.size() == 0)
                {
                    list.add(new JsonProperty(sb.toString()));
                    sb.setLength(0);
                }

            }
            else if (cur == ',' && stack.size() == 0 && stackType.size() == 0)
            {
                if (sb.length() > 0)
                {
                    list.add(new JsonProperty(sb.toString()));
                    sb.setLength(0);
                }
            }
            else
            {
                sb.append(cur);
            }
        }
        if (stack.size() > 0 || stackType.size() > 0)
        {
            list.clear();
            Log.e("Exception","无法解析Json Array对象!");
        }
        else if (sb.length() > 0)
        {
            list.add(new JsonProperty(sb.toString()));
        }
        return list;
    }


    /**
     * Json String解析
     * @param jsonString
     * @return
     */
    private String parseString(String jsonString)
    {
        int len = jsonString.length();
        StringBuilder sb = new StringBuilder();
        boolean conver = false;
        char cur;
        for (int i = 1; i <= len - 2; i++)
        {
            cur = jsonString.charAt(i);
            if (cur == '\\' && !conver)
            {
                conver = true;
            }
            else if (conver == true)
            {
                conver = false;
                if (cur == '\\' || cur == '\"' || cur == '\'' || cur == '/')
                {
                    sb.append(cur);
                }
                else
                {
                    if (cur == 'u')
                    {
                        String temp = new String(new char[] { cur, jsonString.charAt(i + 1), jsonString.charAt(i + 2), jsonString.charAt(i + 3) });
                        sb.append((char)Integer.parseInt(temp, 16));
                        i += 4;
                    }
                    else
                    {
                        switch (cur)
                        {
                            case 'b':
                                sb.append('\b');
                                break;
                            case 'f':
                                sb.append('\f');
                                break;
                            case 'n':
                                sb.append('\n');
                                break;
                            case 'r':
                                sb.append('\r');
                                break;
                            case 't':
                                sb.append('\t');
                                break;
                        }
                    }
                }
            }
            else
            {
                sb.append(cur);
            }
        }
        return sb.toString();
    }

    /**
     * Json Object解析
     * @param jsonString
     * @return
     */
    private JsonObject parseObject(String jsonString)
    {
        return new JsonObject(jsonString);
    }

    /**
     * 定义一个索引器，如果属性是非数组的，返回本身
     * @param index
     * @return
     */
    public JsonProperty get(int index){
        JsonProperty r = null;
        if (this._type == JsonPropertyType.Array)
        {
            if (this._list != null && (this._list.size() - 1) >= index)
            {
                r = this._list.get(index);
            }
        }
        else if (index == 0)
        {
            return this;
        }
        return r;
    }

    /**
     * 提供一个字符串索引，简化对Object属性的访问
     * @param PropertyName
     * @return
     */
    public JsonProperty getProperty(String PropertyName){
        if (this._type == JsonPropertyType.Object)
        {
            return this._object.getProperty(PropertyName);
        }
        else
        {
            return null;
        }
    }

    public void setProperty(String propertyName, JsonProperty property){
        if (this._type == JsonPropertyType.Object)
        {
            this._object.setProperty(propertyName, property);
        }
        else
        {
            Log.e("Exception","Json属性不是对象类型!");
        }
    }

    /**
     * JsonObject值
     * @return
     */
    public JsonObject getObject(){
        if (this._type == JsonPropertyType.Object) {
            return this._object;
        }
        return null;
    }

    /**
     * 字符串值
     * @return
     */
    public String getValue(){
        if (this._type == JsonPropertyType.String) {
            return this._value;
        } else if (this._type == JsonPropertyType.Number) {
            return String.valueOf(this._number);
        } else if (this._type == JsonPropertyType.Integer) {
            return String.valueOf(this._integer);
        }
        return "";
    }

    public JsonProperty add(Object value)
    {
        if (this._type != JsonPropertyType.Null && this._type != JsonPropertyType.Array)
        {
            Log.e("Exception", "Json属性不是Array类型，无法添加元素!");
            return null;
        }
        if (this._list == null)
        {
            this._list = new ArrayList<JsonProperty>();
        }
        JsonProperty jp = new JsonProperty(value);
        this._list.add(jp);
        this._type = JsonPropertyType.Array;
        return jp;
    }

    /**
     * Array值，如果属性是非数组的，则封装成只有一个元素的数组
     * @return
     */
    public List<JsonProperty> getItems(){
        if (this._type == JsonPropertyType.Array)
        {
            return this._list;
        }
        else
        {
            List<JsonProperty> list = new ArrayList<JsonProperty>();
            list.add(this);
            return list;
        }
    }

    /**
     * 获取<code>double</code>值
     * @return
     */
    public double getNumber() {
        if (this._type == JsonPropertyType.Number) {
            return this._number;
        } else {
            try {
                return Double.parseDouble(getObjectValue().toString());
            } catch (Exception e) {
                return Double.NaN;
            }
        }
    }

    public int getInteger(){
        if (this._type == JsonPropertyType.Integer) {
            return this._integer;
        } else if (this._type == JsonPropertyType.Number) {
            return (int)this._number;
        } else {
            try {
                return Integer.parseInt(getObjectValue().toString());
            } catch (Exception e) {
                return Integer.MIN_VALUE;
            }
        }
    }

    public boolean getBoolean() {
        if (this._type == JsonPropertyType.Bool) {
            return this._bool;
        }
        return Boolean.FALSE;
    }

    public void clear()
    {
        this._type = JsonPropertyType.Null;
        this._value = "";
        this._object = null;
        if (this._list != null)
        {
            this._list.clear();
            this._list = null;
        }
    }

    public Object getObjectValue()
    {
        if (this._type == JsonPropertyType.String)
        {
            return this._value;
        }
        else if (this._type == JsonPropertyType.Object)
        {
            return this._object;
        }
        else if (this._type == JsonPropertyType.Array)
        {
            return this._list;
        }
        else if (this._type == JsonPropertyType.Bool)
        {
            return this._bool;
        }
        else if (this._type == JsonPropertyType.Number)
        {
            return this._number;
        } else if (this._type == JsonPropertyType.Integer){
            return this._integer;
        }
        else
        {
            return null;
        }
    }

    public <T extends Class> T getTValue(){
        return ((T)getObjectValue());
    }

    public void setValue(Object value)
    {
        if (value instanceof String) {
            this._type = JsonPropertyType.String;
            this._value = (String)value;
        }
        else if (value instanceof List) {
            this._list = ((List<JsonProperty>)value);
            this._type = JsonPropertyType.Array;
        }
        else if (value instanceof JsonObject) {
            this._object = (JsonObject)value;
            this._type = JsonPropertyType.Object;
        }
        else if (value instanceof Boolean) {
            this._bool = (Boolean)value;
            this._type = JsonPropertyType.Bool;
        }
        else if (value == null) {
            this._type = JsonPropertyType.Null;
        }
        else if (value instanceof Integer){
            this._type = JsonPropertyType.Integer;
            this._integer = (Integer)value;
        }
        else {
            if (SystemTool.isDouble(value.toString())) {
                this._number = Double.parseDouble(value.toString());
                this._type = JsonPropertyType.Number;
            } else {
                this._value = value.toString();
                this._type = JsonPropertyType.String;
            }
        }
    }

    public int getCount(){
        int c = 0;
        if (this._type == JsonPropertyType.Array)
        {
            if (this._list != null)
            {
                c = this._list.size();
            }
        }
        else
        {
            c = 1;
        }
        return c;
    }

    public JsonPropertyType getType(){
        return this._type;
    }

    @Override
    public String toString()
    {
        return this.toString(0);
    }


    public String toString(int level)
    {
        StringBuilder sb = new StringBuilder();
        if (this._type == JsonPropertyType.String) {
            sb.append("\"");
            for (int i = 0; i < this._value.length(); i++)
            {
                char c = this._value.charAt(i);
                if (c == '\\') {
                    sb.append('\\');
                }
                sb.append(c);
            }
            sb.append("\"");
            return sb.toString();
        } else if (this._type == JsonPropertyType.Bool) {
            return this._bool ? "true" : "false";
        } else if (this._type == JsonPropertyType.Number) {
            return String.valueOf(this._number);
        } else if (this._type == JsonPropertyType.Integer){
            return String.valueOf(this._integer);
        } else if (this._type == JsonPropertyType.Null) {
            return "null";
        } else if (this._type == JsonPropertyType.Object) {
            return this._object.toString(level);
        } else {
            if (this._list == null || this._list.size() == 0) {
                sb.append("[]");
            } else {
                if (level > 0) {
                    sb.append((level > 1 ? "\n" : "") + JsonObject.getFormatStr(level - 1) + "[");
                    if (this._list.size() > 0) {
                        for (JsonProperty p : this._list) {
                            sb.append(p.toString(level + 1) + ",");
                        }
                    }
                    if (sb.length() > 1) {
                        sb.deleteCharAt(sb.length() - 1);
                    }
                    sb.append((level > 1 ? "\n" : "") + JsonObject.getFormatStr(level - 1) + "]");
                } else {
                    sb.append("[");
                    if (this._list.size() > 0) {
                        for (JsonProperty p : this._list) {
                            sb.append(p.toString() + ",");
                        }
                    }
                    if (sb.length() > 1) {
                        sb.deleteCharAt(sb.length() - 1);
                    }
                    sb.append("]");
                }
            }
            return sb.toString();
        }
    }

    public static JsonProperty readFile(String path) {
        try {
            String s = FileUtil.ReadFile(path);
            if (!"".equals(s.trim())) {
                return new JsonProperty(s);
            }
        } catch (Exception e) {
            L.WriteExceptionLog("JsonObject", "readFile", e.getMessage());
        }
        return null;
    }
}
